#include "VisImageWrapper.h"

#include "itkMinimumMaximumImageCalculator.h"

#include <QString>

VisImageWrapper::VisImageWrapper()
{
//    m_VolumeMap = new VolumeMap;

    m_LabelToGreyFilter = LabelToGreyFilterType::New();

    m_AxialSlicer = new SlicerWidget(VisWidgetBase::SLICER_AXIAL);
    m_SagittalSlicer = new SlicerWidget(VisWidgetBase::SLICER_SAGITTAL);
    m_CoronalSlicer = new SlicerWidget(VisWidgetBase::SLICER_CORONAL);
    m_VolumeWidget = new VolumeWidget;

    m_VisWidgets.push_back(m_AxialSlicer);
    m_VisWidgets.push_back(m_SagittalSlicer);
    m_VisWidgets.push_back(m_CoronalSlicer);
    m_VisWidgets.push_back(m_VolumeWidget);


    m_Slicers.push_back(m_AxialSlicer);
    m_Slicers.push_back(m_SagittalSlicer);
    m_Slicers.push_back(m_CoronalSlicer);

    connect(m_AxialSlicer, SIGNAL(PointChanged(double*)), m_SagittalSlicer, SLOT(ChangePoint(double*)));
    connect(m_AxialSlicer, SIGNAL(PointChanged(double*)), m_CoronalSlicer, SLOT(ChangePoint(double*)));

    connect(m_SagittalSlicer, SIGNAL(PointChanged(double*)), m_AxialSlicer, SLOT(ChangePoint(double*)));
    connect(m_SagittalSlicer, SIGNAL(PointChanged(double*)), m_CoronalSlicer, SLOT(ChangePoint(double*)));

    connect(m_CoronalSlicer, SIGNAL(PointChanged(double*)), m_AxialSlicer, SLOT(ChangePoint(double*)));
    connect(m_CoronalSlicer, SIGNAL(PointChanged(double*)), m_SagittalSlicer, SLOT(ChangePoint(double*)));

    for (SlicerListIterator it = m_Slicers.begin(); it != m_Slicers.end(); it++)
    {
        connect((*it), SIGNAL(PointChanged(double*)), this, SLOT (SeedPointPicked(double*)));
    }
}

template <class TInputImageType>
DisplayImageType*
VisImageWrapper::ConvertITKToVTK(TInputImageType* inputImage)
{
    typedef itk::ImageToVTKImageFilter<TInputImageType> ConnectorType;
    typedef typename ConnectorType::Pointer ConnectorPointer;

    ConnectorPointer connector = ConnectorType::New();
    connector->SetInput(inputImage);
    connector->Update();

    DisplayImagePointer image = connector->GetOutput();
    image->SetOrigin(inputImage->GetOrigin()[0], inputImage->GetOrigin()[1], inputImage->GetOrigin()[2]);
    image->SetSpacing(inputImage->GetSpacing()[0],
                      inputImage->GetSpacing()[1],
                        inputImage->GetSpacing()[2]);
    image->SetExtent(0, inputImage->GetBufferedRegion().GetSize()[0]-1,
                     0, inputImage->GetBufferedRegion().GetSize()[1]-1,
                     0, inputImage->GetBufferedRegion().GetSize()[2]-1);
    image->SetNumberOfScalarComponents(1);
    image->Update();

    DisplayImagePointer displayImage = DisplayImageType::New();
    displayImage->ShallowCopy(image);
    displayImage->CopyInformation(image);

    double *origin = displayImage->GetOrigin();
    QMessageBox msgBox;
    msgBox.setText("VTK Origin is "+QString::number(origin[2]));
    msgBox.exec();

    return displayImage.GetPointer();
}

void
VisImageWrapper::SetImage(GreyImageType *greyImage)
{
    for (VisWidgetListIterator it = m_VisWidgets.begin(); it != m_VisWidgets.end(); it++)
        (*it)->SetTransformMatrix(m_ImageCoordinateGeometry->GetAxialMatrix());

    for (SlicerListIterator it = m_Slicers.begin(); it != m_Slicers.end(); it++)
        (*it)->SetImage(ConvertITKToVTK<GreyImageType>(greyImage), m_ImageProperties);

    m_VolumeWidget->DisplayBox(m_ImageProperties->dimensions[0],
                               m_ImageProperties->dimensions[1],
                               m_ImageProperties->dimensions[2]);
}

void
VisImageWrapper::SeedPointPicked(double *pos)
{
    double point[3];
    m_ImageCoordinateGeometry->GetITKWorldPoint(pos, point);
    emit SeedPointAccepted(point[0], point[1], point[2]);
}

void
VisImageWrapper::SetVolume(Material *material)
{
    LabelMapPointer volume;

    if (!material->GetVolume().IsNull())
    {
        volume = material->GetVolume();

        m_LabelToGreyFilter->SetInput(volume);
        m_LabelToGreyFilter->Update();

        DisplayImagePointer volumeImage = ConvertITKToVTK<BinaryImageType>(m_LabelToGreyFilter->GetOutput());
        volumeImage->SetScalarTypeToUnsignedLong();
        volumeImage->AllocateScalars();
        volumeImage->Update();

        ContourFilterPointer contourFilter = ContourFilterPointer::New();
        contourFilter->SetValue(0, material->GetLabel());
        contourFilter->SetInput(volumeImage);
        contourFilter->Update();

        PolyDataNormalsPointer polyDataNormals = PolyDataNormalsPointer::New();
        polyDataNormals->SetFeatureAngle(60.0);
        polyDataNormals->SetInput(contourFilter->GetOutput());
        polyDataNormals->Update();

        m_VolumeWidget->SetVolume(material, polyDataNormals->GetOutput());
        for (SlicerListIterator it = m_Slicers.begin(); it != m_Slicers.end(); it++)
            (*it)->SetVolume(material, volumeImage);
    }
}

void
VisImageWrapper::ShowVolume(int label)
{
    for (VisWidgetListIterator it = m_VisWidgets.begin(); it != m_VisWidgets.end(); it++)
        (*it)->ShowVolume(label);
}

void
VisImageWrapper::HideVolume(int label)
{
    for (VisWidgetListIterator it = m_VisWidgets.begin(); it != m_VisWidgets.end(); it++)
        (*it)->HideVolume(label);
}

VisWidgetBase*
VisImageWrapper::GetWidget(VisWidgetBase::VisWidgetType type)
{
    switch(type)
    {
    case (VisWidgetBase::SLICER_AXIAL): return m_AxialSlicer; break;
    case (VisWidgetBase::SLICER_CORONAL): return m_CoronalSlicer; break;
    case (VisWidgetBase::SLICER_SAGITTAL): return m_SagittalSlicer; break;
    case (VisWidgetBase::VOLUME): return m_VolumeWidget; break;
    default:
        return m_AxialSlicer;
    }
}
